/*
 * CCVisu is a tool for visual graph clustering
 * and general force-directed graph layout.
 * This file is part of CCVisu.
 *
 * Copyright (C) 2005-2012  Dirk Beyer
 *
 * CCVisu is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * CCVisu is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with CCVisu; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Please find the GNU Lesser General Public License in file
 * license_lgpl.txt or http://www.gnu.org/licenses/lgpl.txt
 *
 * Dirk Beyer    (firstname.lastname@uni-passau.de)
 * University of Passau, Bavaria, Germany
 */
package org.sosy_lab.ccvisu.clustering;

import java.util.List;

import org.sosy_lab.ccvisu.clustering.interfaces.Clusterer;
import org.sosy_lab.ccvisu.graph.GraphData;
import org.sosy_lab.ccvisu.graph.Group;
import org.sosy_lab.util.Colors;
import org.sosy_lab.util.ProgressingBase;

/**
 * Abstract base class for all clustering algorithms of CCVisu.
 */
public abstract class ClustererBase extends ProgressingBase implements Clusterer, Runnable {

  /** The representation of the graph that should be clustered. */
  protected GraphData graphData;

  /**
   * Constructor.
   * @param graphData  Graph that should be clustered.
   */
  public ClustererBase(GraphData graphData) {
    this.graphData = graphData;
  }

  @Override
  public final List<Group> createClustersOfLayout(GraphData graphData)
      throws InterruptedException {

    assert(graphData != null);

    this.graphData = graphData;
    List<Group> clusters = null;

    try {
      // Do the clustering...
      try {
        // Clear the old clustering.
        graphData.clearGroups();

        // Make the new clustering.
        clusters = internalCreateClustersOfLayout();

        // Remove empty clusters
        // and assign colors to the clusters...
        List<Colors> colors = Colors.getMaxDistanceColors(clusters.size());
        for (int i = clusters.size() - 1; i > -1; i--) {
          Group cluster = clusters.get(i);
          cluster.setColor(colors.get(i).get());
          if (cluster.getNodes().size() == 0) {
            clusters.remove(i);
          }
        }
      } catch (InterruptedException e) {
        graphData.clearGroups();
        throw e;
      }
    }
    finally {
      // Inform about finished process.
      setProgress(0, 0, "Clustering finished.");
    }

    // Return the list of created clusters.
    return clusters;
  }

  @Override
  public void runClusteringAndUpdateGroups(GraphData graphData)
      throws InterruptedException {

    List<Group> clusters = createClustersOfLayout(graphData);

    // Update the graph group list.
    for (int i = clusters.size() - 1; i > -1; i--) {
      Group cluster = clusters.get(i);
      cluster.setName(String.format("Cluster %d", i+1));
      graphData.addGroup(cluster);
    }
  }

  /**
   * Method that does the clustering of the graph.
   * Has to be overwritten by the ancestor.
   *
   * @return  List of found partitions.
   *
   * @throws InterruptedException
   */
  protected abstract List<Group> internalCreateClustersOfLayout()
      throws InterruptedException;

  @Override
  public void run() {
    try {
      runClusteringAndUpdateGroups(graphData);
    } catch (InterruptedException ignored) {}
  }
}
